package com.mdd.admin.controller;

import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxScanPayNotifyResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.mdd.admin.service.order.IOrderService;
import com.mdd.admin.service.refund.IOrderRefundService;
import com.mdd.common.entity.order.Order;
import com.mdd.common.utils.WxPayServiceUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * @author panweiliang
 */
@Slf4j
@RestController
@RequestMapping("/api/pay/wx")
public class WxPayController {

    @Resource
    private IOrderService orderService;

    @Resource
    private IOrderRefundService refundService;

    /**
     * <pre>
     * 查询订单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2)
     * 该接口提供所有微信支付订单的查询，商户可以通过查询订单接口主动查询订单状态，完成下一步的业务逻辑。
     * 需要调用查询接口的情况：
     * ◆ 当商户后台、网络、服务器等出现异常，商户系统最终未接收到支付通知；
     * ◆ 调用支付接口后，返回系统错误或未知交易状态情况；
     * ◆ 调用被扫支付API，返回USERPAYING的状态；
     * ◆ 调用关单或撤销接口API之前，需确认支付状态；
     * 接口地址：https://api.mch.weixin.qq.com/pay/orderquery
     * </pre>
     * <p>
     * 查询订单支付信息
     *
     * @param transactionId 微信订单号
     * @param outTradeNo    商户系统内部的订单号，当没提供transactionId时需要传这个。
     */
    @GetMapping("/queryOrder")
    public WxPayOrderQueryV3Result queryOrder(@RequestParam(required = false) String transactionId,
                                              @RequestParam(required = false) String outTradeNo)
            throws WxPayException {
        Order order = orderService.getBySn(outTradeNo);
        return WxPayServiceUtils.wxPayService(order.getPayChannel()).queryOrderV3(transactionId, outTradeNo);
    }

    /**
     * <pre>
     * 关闭订单
     * 应用场景
     * 以下情况需要调用关单接口：
     * 1. 商户订单支付失败需要生成新单号重新发起支付，要对原订单号调用关单，避免重复支付；
     * 2. 系统下单后，用户支付超时，系统退出不再受理，避免用户继续，请调用关单接口。
     * 注意：订单生成后不能马上调用关单接口，最短调用时间间隔为5分钟。
     * 接口地址：https://api.mch.weixin.qq.com/pay/closeorder
     * 是否需要证书：   不需要。
     * </pre>
     *
     * @param outTradeNo 商户系统内部的订单号
     *                   关闭订单
     */
    @GetMapping("/closeOrder")
    public void closeOrder(@RequestParam("outTradeNo") String outTradeNo) throws Exception {
        Order order = orderService.getBySn(outTradeNo);
        WxPayServiceUtils.wxPayService(order.getPayChannel()).closeOrderV3(outTradeNo);
    }

    //  支付回调通知处理
    @PostMapping("/notify/order")
    public String parseOrderNotifyResult(@RequestBody String xmlData) throws Exception {
        log.info("支付回调通知处理,原生xml数据,xmlData:{}", xmlData);

        final WxPayOrderNotifyResult notifyResult = WxPayServiceUtils.wxPayService(null).parseOrderNotifyResult(xmlData);
        log.info("支付回调通知处理,解析后数据,parseOrderNotifyResult:{}", notifyResult);
        String transactionId = notifyResult.getTransactionId();
        String outTradeNo = notifyResult.getOutTradeNo();
        boolean flag = this.orderService.updateOrderStatusToPaid(outTradeNo, transactionId);
        return flag ? WxPayNotifyResponse.success("成功") : WxPayNotifyResponse.fail("失败");
    }

    //  退款回调通知处理
    @PostMapping("/notify/refund")
    public String parseRefundNotifyResult(@RequestBody String xmlData) throws WxPayException {
        log.info("退款回调通知处理原生数据,xmlData:{}", xmlData);
        final WxPayRefundNotifyResult result = WxPayServiceUtils.wxPayService(null).parseRefundNotifyResult(xmlData);
        log.info("退款回调通知处理,parseRefundNotifyResult:{}", result);
        boolean flag = refundService.updateOrderStatusToPaid(result.getReqInfo());
        return flag ? WxPayNotifyResponse.success("成功") : WxPayNotifyResponse.fail("失败");
    }

    //  扫码支付回调通知处理
    @PostMapping("/notify/scanpay")
    public String parseScanPayNotifyResult(String xmlData) throws WxPayException {
        final WxScanPayNotifyResult result = WxPayServiceUtils.wxPayService(null).parseScanPayNotifyResult(xmlData);
        // TODO 根据自己业务场景需要构造返回对象
        return WxPayNotifyResponse.success("成功");
    }

}

